﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MetaProperties.Core.EventFilters
{
    using System.Threading;

    using Framework;

    /// <summary>
    /// Base class for a dispatching event filter.
    /// </summary>
    public abstract class DispatchingEventFilterBase : IEventFilter
    {
        /// <summary>
        /// The default sync context.
        /// </summary>
        private readonly ISynchronizationContextContainer deafultSynchronizationContext;

        /// <summary>
        /// The specified sync context.
        /// </summary>
        private ISynchronizationContextContainer contextContainer;

        /// <summary>
        /// Initializes a new instance of the <see cref="DispatchingEventFilterBase"/> class.
        /// </summary>
        public DispatchingEventFilterBase()
        {
            this.deafultSynchronizationContext = new SynchronizationContextContainer(SynchronizationContext.Current);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="DispatchingEventFilterBase"/> class.
        /// </summary>
        /// <param name="context">The context.</param>
        public DispatchingEventFilterBase(ISynchronizationContextContainer context)
        {
            this.deafultSynchronizationContext = context;
        }

        /// <summary>
        /// Sets the MetaProperty configuration.
        /// </summary>
        /// <param name="configuration">The configuration.</param>
        public void SetMetaPropertyConfiguration(MetaPropertyConfiguration configuration)
        {
            this.MetaPropertyConfiguration = configuration;
        }

        /// <summary>
        /// Performs filtering of the event.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="args">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        /// <param name="pipeline">The pipeline.</param>
        public void PerformFilter(object sender, EventArgs args, IFilterPipeline pipeline)
        {
            if (this.MetaPropertyConfiguration == null)
            {
                throw new Exception("MetaPropertyConfiguration has not been set.");
            }

            if (this.contextContainer == null)
            {
                this.contextContainer = this.MetaPropertyConfiguration.GetSynchronizationContextContainer();

                if (this.contextContainer == null)
                {
                    this.contextContainer = this.deafultSynchronizationContext;

                    if (this.contextContainer == null)
                    {
                        throw new Exception("ISynchronizationContextContainer was null.");
                    }
                }
            }

            this.Resume(sender, args, pipeline);
        }

        /// <summary>
        /// Gets the synchronization context container.
        /// </summary>
        /// <value>The synchronization context container.</value>
        protected ISynchronizationContextContainer SynchronizationContextContainer
        {
            get
            {
                return this.contextContainer;
            }
        }

        /// <summary>
        /// Resumes the event.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="args">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        /// <param name="pipeline">The pipeline.</param>
        protected abstract void Resume(object sender, EventArgs args, IFilterPipeline pipeline);

        /// <summary>
        /// Gets or sets the meta property configuration.
        /// </summary>
        /// <value>The meta property configuration.</value>
        private MetaPropertyConfiguration MetaPropertyConfiguration
        {
            get;
            set;
        }
    }
}